flutter 开发技巧

您所在的位置:网站首页 flutter 动画效果粒子 flutter 开发技巧

flutter 开发技巧

2023-06-01 00:57| 来源: 网络整理| 查看: 265

本文主要包含两个方面:【路由导航】和【路由传值】

路由导航

Flutter中管理多个页面时有两个核心概念和类:Route和Navigator。 一个route是一个屏幕或页面的抽象,Navigator是管理route的Widget。Navigator可以通过route入栈和出栈来实现页面之间的跳转。 路由一般分为静态路由(即命名路由)和动态路由。 ###静态路由(即命名路由) 静态路由在通过Navigator跳转之前,需要在MaterialApp组件内显式声明路由的名称,而一旦声明,路由的跳转方式就固定了。通过在MaterialApp内的routes属性进行显式声明路由的定义。

class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( initialRoute: "/", // 默认加载的界面,这里为RootPage routes: { // 显式声明路由 // "/":(context) => RootPage(), "/A":(context) => Apage(), "/B":(context) => Bpage(), "/C":(context) => Cpage(), }, home: RootPage(), ); } } 注意:如果指定了home属性,routes表则不能再包含此属性。 如上代码中【home: RootPage()】 和 【"/":(context) => RootPage()】两则不能同时存在。

例如:RootPage跳转Apage即:RootPage?—>Apage

Navigator.of(context).pushNamed("/A");

一般方法中带有Name多数是通过静态路由完成跳转的,如pushNamed、pushReplacementNamed、pushNamedAndRemoveUntil等。 ###动态路由 动态路由无需在MaterialApp内的routes中注册即可直接使用:RootPage —> Apage

Navigator.of(context).push(MaterialPageRoute( builder: (context) => Apage(), ));

动态路由中,需要传入一个Route,这里使用的是MaterialPageRoute?,它可以使用和平台风格一致的路由切换动画,在iOS上左右滑动切换,Android上会上下滑动切换。也可以使用CupertinoPageRoute?实现全平台的左右滑动切换。 当然也可以自定义路由切换动画,使用PageRouteBuilder:使用FadeTransition?做一个渐入过渡动画。

Navigator.of(context).push( PageRouteBuilder( transitionDuration: Duration(milliseconds: 250), // //动画时间为0.25秒 pageBuilder: (BuildContext context,Animation animation, Animation secondaryAnimation){ return FadeTransition( //渐隐渐入过渡动画 opacity: animation, child: Apage() ); } ) );

到现在为止,可能对路由有了一定的认识,,下面就结合具体方法来详细说明。 在这之前有必要说明:?Navigator.of(context).push和Navigator.push两着并没有特别的区别,看源码也得知,后者其实就是调用了前者。?of:获取Navigator当前已经实例的状态。 ###pop 返回当前路由栈的上一个界面。?Navigator.pop(context);

push / pushNamed :

见上,两者运行效果相同,只是调用不同,都是将一个page压入路由栈中。直白点就是push是把界面直接放入,pushNames是通过路由名的方式,通过router使界面进入对应的栈中。 结果:直接在原来的路由栈上添加一个新的?page。

pushReplacement / pushReplacementNamed / popAndPushNamed

替换路由,顾名思义替换当前的路由。 例如

2675141-de7b4cb63fcb1d83.png

由图可知在BPage使用替换跳转到Cpage的时候,Bpage被Cpage替换了在堆栈中的位置而移除栈,CPage默认返回的是APage。

pushReplacement 使用的动态路由方式跳转: Navigator.of(context).pushReplacement(MaterialPageRoute( builder: (context) => Cpage(), )); pushReplacementNamed 使用的静态路由方式, Navigator.of(context).pushReplacementNamed("/C");

两者运行效果相同。

popAndPushNamed: Navigator.of(context).popAndPushNamed("/C");

其实和上面两个方法运行的结果也是一致,区别就是动画效果不一样:BPage?—>CPage的时候,CPage会同时有pop的转场效果和从BPage页push的转场效果。简单来说就是CPage先pop到BPage,在push到CPage。(不知道是不是卡顿的原因,笔者看起来区别不大)

综上:3中方法结果一样,只是调用方式和过渡动画的区别,开发者自行选择。

pushAndRemoveUntil / pushNamedAndRemoveUntil

在使用上述方式跳转时,会按次序移除其他的路由,直到遇到被标记的路由(predicate函数返回了true)时停止。若 没有标记的路由,则移除全部。 当路由栈中存在重复的标记路由时,默认移除到最近的一个停止。

第一种 // 移除全部 Navigator.pushAndRemoveUntil(context, MaterialPageRoute(builder: (_) => CPage()), (Route router) => router == null);

// 移除全部 Navigator.of(context).pushNamedAndRemoveUntil("/C", (Route router) => router == null);

此时的路由栈示意图:

2675141-364a8005348f7aec.png

可知出了要push的CPage,当前路由栈中所有的路由都被移除,CPage变成根路由。

第二种:移除到RootPage停止 // "/"即为RootPage,标记后,移除到该路由停止移除 Navigator.pushAndRemoveUntil(context, MaterialPageRoute(builder: (_) => CPage()), ModalRoute.withName('/')) 或 Navigator.pushAndRemoveUntil(context, MaterialPageRoute(builder: (_) => CPage()), (Route router) => router.settings.name == "/"); // 只是写法不一样

Navigator.of(context).pushNamedAndRemoveUntil("/C", (Route router) => router.settings.name == "/"); 或 Navigator.of(context).pushNamedAndRemoveUntil("/C", ModalRoute.withName("/"));

此时的路由栈示意图:

image.png

push到CPage的时候,移除到RootPage停止,CPage默认返回RootPage。

popUntil

返回到指定的标记路由,若标记的路由为null,则程序退出,慎用!!! 有时候我们需要根据业务需求判断:可能返回上一级路由,也可能返回上上级路由或是返回指定的路由等。这个时候就不能使用Replacement和RemoveUntil来替换、移除路由了。 例如:

在这里插入图片描述

Navigator.of(context).popUntil((route) => route.settings.name == "/"); 或 Navigator.of(context).popUntil(ModalRoute.withName("/"));

再例如:

image.png

要实现上述功能,从CPage返回到APage,并且不在MaterialApp内的routes属性进行显式声明路由。因为笔者觉得一个应用程序的界面太多了,如果每个界面都要显示声明路由,实在是不优雅。 因为需要返回APage,还是需要标记路由,所有我们在之前跳转APage的时候设置RouteSettings,如下:

// 设置APage的RouteSettings Navigator.of(context).push(MaterialPageRoute( settings: RouteSettings(name:"/A"), builder: (context) => APage(), ));

在CPage需要返回的时候,调用就行:

Navigator.of(context).popUntil(ModalRoute.withName("/A"));

这样代码看起来很优雅,不会冗余。 另:

// 返回根路由 Navigator.of(context).popUntil((route) => route.isFirst); canPop

用来判断是否可以导航到新页面,返回的bool类型,一般是在设备带返回的物理按键时需要判断是否可以pop。

maybePop

可以理解为canPop的升级,maybePop?会自动判断。如果当前的路由可以pop,则执行当前路由的pop操作,否则将不执行。

removeRoute/removeRouteBelow

删除路由,同时执行Route.dispose操作,无过渡动画,正在进行的手势也会被取消。

removeRoute

image.png

BPage被移除了当前的路由栈。 如果在当前页面调用removeRoute?,则类似于调用pop方法,区别就是无过渡动画,所以removeRoute?也可以用来返回上一页。

removeRouteBelow

移除指定路由底层的临近的一个路由,并且对应路由不存在的时候会报错。 同上。

综上:这个两个方法一般情况下很少用,而且必须要持有对应的要移除的路由。 一般用于立即关闭,如移除当前界面的弹出框等。

路由传值

常见的路由传值分为两个方面:

向下级路由传值返回上级路由时传值

要注意的是,我们一般说静态路由不能传值,并不是说一定不能用于传值,而是因为静态路由一般需要在MaterialApp内的routes属性进行显式声明,在这里使用构造函数传值无实际意义。 如:

MaterialApp( initialRoute: "/", // 默认加载的界面,这里为RootPage routes: { // 显式声明路由 "/":(context) => RootPage(), "/A":(context) => APage("title"), // 在这里传参无实际意义,一般需要传入的参数都是动态变化的 "/B":(context) => BPage(), "/C":(context) => CPage(), }, // home: RootPage(), ); 向下级路由传值 1、构造函数传值

首先构造一个可以带参数的构造函数:

class APage extends StatefulWidget { String title; APage(this.title); @override _APageState createState() => _APageState(); }

在路由跳转的时候传值:

Navigator.of(context).push(MaterialPageRoute( builder: (context) => APage("这是传入的参数"), ));

在APage拿到传入的值:

// 在 StatefulWidget 使用[widget.参数名] Container( child: Text(widget.title), ) 复制代码 2、ModalRoute 传值

在Navigator.of(context).push的跳转方式中,MaterialPageRoute?的构造参数中 可以看到有RouteSettings的属性,RouteSettings就是当前路由的基本信息

const RouteSettings({ this.name, this.isInitialRoute = false, this.arguments, // 存储路由相关的参数Object });

路由跳转时设置传递参数:

Navigator.of(context).push(MaterialPageRoute( settings: RouteSettings(name:"/A",arguments: {"argms":"这是传入A的参数"}), builder: (context) => APage(), )); 或使用静态路由pushName: Navigator.of(context).pushNamed("/A",arguments:{"argms":"这是传入A的参数"}); 复制代码

在APage中取值:

Map argms = ModalRoute.of(context).settings.arguments; print(argms["argms"]); 复制代码 返回上级路由时传值

就是在调用APage中调用pop返回路由的时候传参

Navigator.of(context).pop("这是pop返回的参数值"); 复制代码

在上一级路由获取:

Navigator.of(context).push(MaterialPageRoute( builder: (context) => APage(), )).then((value){ // 获取pop的传值 print(value); }); 或 String value = await Navigator.of(context).pushNamed('/xxx');


【本文地址】


今日新闻


推荐新闻


    CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3